#include <gtest/gtest.h>
#include <string>
#include "../mqserver/mq_host.hpp"

const std::string exch1 = "exch1";
const std::string exch2 = "exch2";
const std::string exch3 = "exch3";

const std::string queue1 = "mq1";
const std::string queue2 = "mq2";
const std::string queue3 = "mq3";

class HostTest : public testing::Test
{
public:
    virtual void SetUp() override
    {
        const std::string hname = "host1";
        const std::string basedir = "./data/host1/message/";
        const std::string dbfile = "./data/host1/host1.db";
        host_ = std::make_shared<mqserver::VirtualHost>(hname, basedir, dbfile);

        std::unordered_map<std::string, std::string> empty_map;

        host_->declareExchange(exch1, proto::message::ExchangeType::DIRECT, true, false, empty_map);
        host_->declareExchange(exch2, proto::message::ExchangeType::DIRECT, true, false, empty_map);
        host_->declareExchange(exch3, proto::message::ExchangeType::DIRECT, true, false, empty_map);

		host_->declareQueue(queue1, true, false, false, empty_map);
		host_->declareQueue(queue2, true, false, false, empty_map);
		host_->declareQueue(queue3, true, false, false, empty_map);

		host_->bind(exch1, queue1, "news.music.#");
		host_->bind(exch1, queue2, "news.music.#");
		host_->bind(exch1, queue3, "news.music.#");

		host_->bind(exch2, queue1, "news.music.#");
		host_->bind(exch2, queue2, "news.music.#");
		host_->bind(exch2, queue3, "news.music.#");

		host_->bind(exch3, queue1, "news.music.#");
		host_->bind(exch3, queue2, "news.music.#");
		host_->bind(exch3, queue3, "news.music.#");

		host_->basicPublish(queue1, nullptr, "queue1 message[1]");
		host_->basicPublish(queue1, nullptr, "queue1 message[2]");
		host_->basicPublish(queue1, nullptr, "queue1 message[3]");

		host_->basicPublish(queue2, nullptr, "queue2 message[1]");
		host_->basicPublish(queue2, nullptr, "queue2 message[2]");
		host_->basicPublish(queue2, nullptr, "queue2 message[3]");

		host_->basicPublish(queue3, nullptr, "queue3 message[1]");
		host_->basicPublish(queue3, nullptr, "queue3 message[2]");
		host_->basicPublish(queue3, nullptr, "queue3 message[3]");
    }
    virtual void TearDown() override { host_->clear(); }
public:
    mqserver::VirtualHostPtr host_; 
};

TEST_F(HostTest, init_test)
{
    ASSERT_EQ(host_->existsExchange(exch1), true);
    ASSERT_EQ(host_->existsExchange(exch2), true);
    ASSERT_EQ(host_->existsExchange(exch3), true);

	ASSERT_EQ(host_->existsQueue(queue1), true);
	ASSERT_EQ(host_->existsQueue(queue2), true);
	ASSERT_EQ(host_->existsQueue(queue3), true);

	ASSERT_EQ(host_->existsBinding(exch1, queue1), true);
	ASSERT_EQ(host_->existsBinding(exch1, queue2), true);
	ASSERT_EQ(host_->existsBinding(exch1, queue3), true);

	ASSERT_EQ(host_->existsBinding(exch2, queue1), true);
	ASSERT_EQ(host_->existsBinding(exch2, queue2), true);
	ASSERT_EQ(host_->existsBinding(exch2, queue3), true);
	
	ASSERT_EQ(host_->existsBinding(exch3, queue1), true);
	ASSERT_EQ(host_->existsBinding(exch3, queue2), true);
	ASSERT_EQ(host_->existsBinding(exch3, queue3), true);

	mqserver::MessagePtr msg1_1 = host_->basicConsume(queue1);
	ASSERT_EQ(msg1_1->payload().body(), std::string("queue1 message[1]"));

	mqserver::MessagePtr msg1_2 = host_->basicConsume(queue1);
	ASSERT_EQ(msg1_2->payload().body(), std::string("queue1 message[2]"));

	mqserver::MessagePtr msg1_3 = host_->basicConsume(queue1);
	ASSERT_EQ(msg1_3->payload().body(), std::string("queue1 message[3]"));

	mqserver::MessagePtr msg1_4 = host_->basicConsume(queue1);
	ASSERT_EQ(msg1_4.get(), nullptr);

	mqserver::MessagePtr msg2_1 = host_->basicConsume(queue2);
	ASSERT_EQ(msg2_1->payload().body(), std::string("queue2 message[1]"));

	mqserver::MessagePtr msg2_2 = host_->basicConsume(queue2);
	ASSERT_EQ(msg2_2->payload().body(), std::string("queue2 message[2]"));

	mqserver::MessagePtr msg2_3 = host_->basicConsume(queue2);
	ASSERT_EQ(msg2_3->payload().body(), std::string("queue2 message[3]"));

	mqserver::MessagePtr msg2_4 = host_->basicConsume(queue2);
	ASSERT_EQ(msg2_4.get(), nullptr);	
}

TEST_F(HostTest, remove_exchange)
{
	host_->deleteExchange(exch1);
	ASSERT_EQ(host_->existsExchange(exch1), false);

	ASSERT_EQ(host_->existsBinding(exch1, queue1), false);
	ASSERT_EQ(host_->existsBinding(exch1, queue2), false);
	ASSERT_EQ(host_->existsBinding(exch1, queue3), false);
}

TEST_F(HostTest, remove_queue)
{
	host_->deleteQueue(queue1);
	ASSERT_EQ(host_->existsQueue(queue1), false);

	ASSERT_EQ(host_->existsBinding(exch1, queue1), false);
	ASSERT_EQ(host_->existsBinding(exch2, queue1), false);
	ASSERT_EQ(host_->existsBinding(exch3, queue1), false);

	mqserver::MessagePtr msg = host_->basicConsume(queue1);
	ASSERT_EQ(msg.get(), nullptr);
}

// 每个单元测试都是独立的数据(都会经过SetUp初始化)
TEST_F(HostTest, ack_message)
{
	mqserver::MessagePtr msg1_1 = host_->basicConsume(queue1);
	ASSERT_EQ(msg1_1->payload().body(), std::string("queue1 message[1]"));
	ASSERT_EQ(host_->basicAck(queue1, msg1_1->payload().properties().id()), true);

	mqserver::MessagePtr msg1_2 = host_->basicConsume(queue1);
	ASSERT_EQ(msg1_2->payload().body(), std::string("queue1 message[2]"));
	ASSERT_EQ(host_->basicAck(queue1, msg1_2->payload().properties().id()), true);

	mqserver::MessagePtr msg1_3 = host_->basicConsume(queue1);
	ASSERT_EQ(msg1_3->payload().body(), std::string("queue1 message[3]"));
	ASSERT_EQ(host_->basicAck(queue1, msg1_3->payload().properties().id()), true);
}

int main(int argc,char *argv[])
{
    testing::InitGoogleTest(&argc, argv);
    (void)RUN_ALL_TESTS();
    return 0;
}